import java.util.ArrayList;

public class Rule {

	String name;

	String regex;

	NFA n;

	boolean token;
	

	static int count=0;
	int priority;
	
	
	public Rule(String s, ScannerGenerator sg) {

		name = s.substring(0, s.indexOf(' '));
		
		regex = s.substring(s.indexOf(' ') + 1, s.length());

		while(regex.charAt(regex.length()-1)==' '){
			regex=regex.substring(0,regex.length()-1);
		}
		
		
		priority=count++;
		
		if(regex.indexOf('[') < 0) token=true;
		
		try {
			n = newParse(regex,sg);
			n.changeName(name);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		// System.out.println(name);

	}

	public Rule(NFA n) {
		this.n = n;
		this.name = "blah";
	}

	public String getName() {
		return name;
	}

	public static NFA newParse(String s, ScannerGenerator sg){
		RegexParser rp = new RegexParser(s,sg);
		return rp.parse();
	}
	
	//No longer used, scrapped
//	public static NFA parse(String name2, String s, ScannerGenerator sg)
//			throws Exception {
//		if (s.length() == 0) {
//			throw (new Exception("tried to parse empty string"));
//		}
//		NFA returned = NFA.emptyNFA();
//		char current = ' ';
//		int endIndex, index;
//		String substring;
//		for (index = 0; index < s.length() - 1; index++) {
//			current = s.charAt(index);
//			switch (current) {// brackets, parens, backslash, union, plus, star,
//								// period, caret, single and double quote
//			case '[': // bracket
//				endIndex = s.indexOf(']', index + 1);
//				if (index + 1 < endIndex) {
//					substring = s.substring(index + 1, endIndex);
//					if (substring.charAt(0) != '^') {
//						returned.concat(createNFAforBracket(name2, substring));
//					} else {
//						returned.concat(createNFAforBracketNot(name2,
//								s.substring(index), sg));
//
//						System.out.println("ignored "+ s.substring(index));
//						index = s.length();//Ignore rest of string
//					}
//				} else {// empty brackets
//					returned.concat(NFA.emptyNFA());
//				}
//				if(index<s.length())
//					index = endIndex;
//				break;
//			case '(':
//				endIndex = reverseIndex(s, ')');
//				if (index + 1 < endIndex) {
//					substring = s.substring(index + 1, endIndex);
//					returned.concat(parse(name2, substring, sg));
//				} else {// empty brackets
//					returned.concat(NFA.emptyNFA());
//				}
//				index = endIndex;
//
//				break;
//			case '\\':
//				returned.concat(new NFA("escaped", s.charAt(index + 1), s
//						.charAt(index + 1), ' '));
//				index++;
//				break;
//			case '|':
//				char nextChar = s.charAt(index + 1);
//				if (nextChar == ' ' || nextChar == '\t') {
//					returned.union(NFA.emptyNFA());
//				} else {
//					returned.union(parse(name2, s.substring(index + 1), sg));
//				}
//				index = s.length();
//				break;
//			case '.':
//
//				break;
//			case '\'':
//
//				break;
//			case '\"':
//
//				break;
//			case ' ':
//				break;
//			case '$':// check for identifier
//				endIndex = index;
//				while (endIndex < s.length()) {
//					char cha = s.charAt(endIndex);
//					if (cha == '[' || cha == ']' || cha == '(' || cha == ')'
//							|| cha == ' ' || cha == '\\' || cha == '*'
//							|| cha == '+' || cha == '|' || cha == '.'
//							|| cha == '\'' || cha == '\"') {
//						break;
//					}
//					endIndex++;
//				}// end of while
//				returned.concat(sg.getRule(s.substring(index, endIndex))
//						.getNFA().cloneNFA(name2, false));
//				index = endIndex - 1;
//				break;
//			case '*':
//				returned.star();
//				break;
//			case '+':
//				returned.plus();
//				break;
//			default:
//				returned.concat(new NFA("char", current, current, ' '));
//				break;
//			}
//
//		}// end of for loop
//			// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//			// last character case
//		if (index == s.length() - 1) {
//			char lastChar = s.charAt(index);
//			switch (lastChar) {
//			case '[':
//				// error
//				System.out.println("error in parse. Last char was [");
//				break;
//			case '(':
//				// error
//				System.out.println("error in parse. Last Char was (");
//				break;
//			case '\\':
//				System.out.println("error in parse. Last Char was \\");
//				break;
//			case '|':
//				returned.union(NFA.emptyNFA());
//				break;
//			case '.':
//
//				break;
//			case '\'':
//
//				break;
//			case '\"':
//
//				break;
//			case ' ':
//				break;
//			case '$':// check for identifier
//				System.out.println("error in parse. Last Char was $");
//				break;
//			case '*':
//				returned.star();
//				break;
//			case '+':
//				returned.plus();
//				break;
//			default:
//				returned.concat(new NFA("char", current, current, ' '));
//				break;
//			}
//		}
//
//		return returned;
//	}

	public boolean matchString(String s) {
		return n.match(s);
	}

	public NFA getNFA() {

		return n.cloneNFA(false);
	}
	
	public NFA getNFANoCopy(){
		return n;
	}

	private static NFA createNFAforBracket(String name2, String withinBrackets) {
		NFA returned = NFA.blankNFA();
		returned.changeName(name2);
		int index;
		char c;
		for (index = 0; index < withinBrackets.length() - 1; index++) {
			c = withinBrackets.charAt(index);
			if (c == '\\') {
				index++;
				c = withinBrackets.charAt(index);
			}
			if (withinBrackets.charAt(index + 1) == '-') {
				returned.union(new NFA(name2, withinBrackets.charAt(index),
						withinBrackets.charAt(index + 2), ' '));
				index += 2;
			} else {
				returned.union(new NFA(name2, withinBrackets.charAt(index),
						withinBrackets.charAt(index), ' '));

			}

		}// end of for loop

		return returned;
	}

	public String getRegex() {

		return regex;
	}

	private static NFA createNFAforBracketNot(String name2, String s,
			ScannerGenerator sg) {
		int bracketIndex = 2;
		NFA rule;
		while (bracketIndex < s.length()) {
			char cha = s.charAt(bracketIndex);
			if (cha == ']') {
				break;
			}
			bracketIndex++;
		}// end of while
		String bracket = s.substring(2, bracketIndex);
		int index = Math.max(s.indexOf("IN $", bracketIndex),
				s.indexOf("IN$", bracketIndex));
		if (index > 0) { // in rule
			rule = sg.getRule(s.substring(s.indexOf('$'))).getNFA()
					.cloneNFA(name2, false);
		} else {// in range
			while (bracketIndex < s.length()) {
				char cha = s.charAt(bracketIndex);
				if (cha == '[') {
					break;
				}
				bracketIndex++;
			}// end of while
			rule = createNFAforBracket(name2, s.substring(bracketIndex + 1));
		}

		NFA returned = NFA.blankNFA();
		returned.changeName(name2);
		index = 0;
		char c;
		ArrayList<Integer> a = new ArrayList<Integer>();
		for (index = 0; index < bracket.length(); index++) {
			c = bracket.charAt(index);
			if (c == '\\') {
				index++;
				c = bracket.charAt(index);
			}
			if (bracket.length()>index+2 &&bracket.charAt(index + 1) == '-') {
				a.add(c * -1);
				a.add((s.charAt(index + 2)) * -1);
				index += 2;
			} else {
				a.add((int) c);
			}
		}// end of for loop
		int last = 0;
		int value;
		for (index = 0; index < a.size(); index++) {
			value = a.get(index).intValue();
			if (value < 0) {
				returned.union(new NFA(name2, last + 1, (value * -1) - 1, ' ',
						rule, true));
				last = a.get(index + 1).intValue() * -1;
			} else {
				returned.union(new NFA(name2, last + 1,
						a.get(index).intValue() - 1, ' ', rule, true));
				last = a.get(index).intValue();
			}
		}
		returned.union(new NFA(name2, last + 1,
						256 - 1, ' ', rule, true));

		return returned;
	}
	
	static int reverseIndex(String s, char c){
		for(int i=s.length()-1; i>=0; i++){
			if(s.charAt(i)==c)
				return i;
		}
		return -1;
	}
	
	public boolean isToken(){
		return token;
	}
	
	public int getPriority(){
		return priority;
	
	}

}
